package com.it.sun.yuebike.framework.util;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONUtil;
import com.it.sun.yuebike.framework.config.MinioConfig;
import io.minio.MinioClient;
import io.minio.PutObjectOptions;
import io.minio.errors.*;
import lombok.Data;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringJoiner;

/**
 * @ClassName com.it.sun.yuebike.framework.util.MinioUtils
 * @Author sunmannian
 * @Date 2021/6/1 17:36
 * @Version V1.0
 * Description  <minio工具类>
 * Copyright (C) 北京中电兴发科技有限公司  since 2021/6/1
 */

public class MinioUtils {

    public static MinioClient client;

    public static final long DEFAULT_PART_SIZE = 5L * 1024 * 1024 * 1024;

    public static MinioConfig.MinioProperties properties;

    /**
     * <描述方法功能>
     * <上传文件>
     *
     * @param file
     * @param filename
     * @param bucketName
     * @return java.lang.String
     * @Author sunmannian
     * @Date 2021/6/2 10:14
     **/
    public static String upload(MultipartFile file, String bucketName, String filename) {
        try {
            if (!client.bucketExists(bucketName)) {
                client.makeBucket(bucketName);
                client.setBucketPolicy(bucketName, JSONUtil.parse(getBucketPolicy(bucketName),
                        JSONConfig.create().setDateFormat("yyyy-MM-dd")).toStringPretty());
            }
            InputStream inputStream = file.getInputStream();
            PutObjectOptions putObjectOptions = new PutObjectOptions(file.getSize(), DEFAULT_PART_SIZE);
            client.putObject(bucketName, filename, inputStream, putObjectOptions);
            IoUtil.close(inputStream);
            return getObjectUrl(bucketName, filename);
        } catch (ErrorResponseException e) {
            e.printStackTrace();
        } catch (InsufficientDataException e) {
            e.printStackTrace();
        } catch (InternalException e) {
            e.printStackTrace();
        } catch (InvalidBucketNameException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (InvalidResponseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (XmlParserException e) {
            e.printStackTrace();
        } catch (RegionConflictException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * <描述方法功能>
     * <获取上传对象的下载地址>
     *
     * @param bucketName
     * @param fileName
     * @return java.lang.String
     * @Author sunmannian
     * @Date 2021/6/2 14:42
     **/
    private static String getObjectUrl(String bucketName, String fileName) {
        return new StringJoiner("/").add(properties.getDownloadUrl()).add(bucketName).add(fileName).toString();
    }

    /**
     * <描述方法功能>
     * <上传文件>
     *
     * @param file
     * @param bucketName
     * @return java.lang.String
     * @Author sunmannian
     * @Date 2021/6/2 10:25
     **/
    public static String upload(MultipartFile file, String bucketName) {
        return upload(file, bucketName, file.getOriginalFilename());
    }

    /**
     * <描述方法功能>
     * <下载文件>
     *
     * @param bucketName
     * @param filename
     * @return java.io.InputStream
     * @Author sunmannian
     * @Date 2021/6/2 10:34
     **/
    public static InputStream download(String bucketName, String filename) {

        try {
            if (client.bucketExists(bucketName)) {
                return client.getObject(bucketName, filename);
            }
        } catch (ErrorResponseException e) {
            e.printStackTrace();
        } catch (InsufficientDataException e) {
            e.printStackTrace();
        } catch (InternalException e) {
            e.printStackTrace();
        } catch (InvalidBucketNameException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (InvalidResponseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (XmlParserException e) {
            e.printStackTrace();
        }
        return null;
    }


    public static void downloadForBrowser(HttpServletResponse response, String filename, String bucketName) {
        InputStream inputStream = download(bucketName, filename);
        if (null != inputStream) {
            try {
                ServletOutputStream outputStream = response.getOutputStream();
                response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + filename);
                IoUtil.copy(inputStream, outputStream);
            } catch (IOException e) {
                responseDownloadFailed(response);
            }
        } else {
            responseDownloadFailed(response);
        }
    }

    /**
     * <描述方法功能>
     * <删除文件>
     *
     * @param bucketName
     * @param filename
     * @return boolean
     * @Author sunmannian
     * @Date 2021/6/2 10:55
     **/
    public static boolean deleteFile(String bucketName, String filename) {
        try {
            client.removeObject(bucketName, filename);
            return true;
        } catch (ErrorResponseException e) {
            e.printStackTrace();
        } catch (InsufficientDataException e) {
            e.printStackTrace();
        } catch (InternalException e) {
            e.printStackTrace();
        } catch (InvalidBucketNameException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (InvalidResponseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (XmlParserException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * <描述方法功能>
     * <下载文件失败响应>
     *
     * @param response
     * @return void
     * @Author sunmannian
     * @Date 2021/6/2 10:51
     **/
    private static void responseDownloadFailed(HttpServletResponse response) {
        response.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
        try {
            response.getWriter().write(JSONUtil.toJsonPrettyStr(ResultUtils.error("下载文件失败!")));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Data
    private static class BucketPolicy {

        private List<Statement> Statement;

        private LocalDate Version = LocalDate.of(2012, 10, 17);

        @Data
        static class Statement {

            String Effect = "Allow";

            Principal Principal = new Principal();

            List<String> Action = CollectionUtil.newArrayList
                    (BucketPolicy.Action.AbortMultipartUpload.action,
                            BucketPolicy.Action.DeleteObject.action,
                            BucketPolicy.Action.GetObject.action,
                            BucketPolicy.Action.ListMultipartUploadParts.action,
                            BucketPolicy.Action.PutObject.action);
            List<String> Resource;

            @Data
            class Principal {
                List<String> AWS = CollectionUtil.newArrayList("*");
            }
        }

        enum Action {

            AbortMultipartUpload("s3:AbortMultipartUpload"),

            DeleteObject("s3:DeleteObject"),

            GetObject("s3:GetObject"),

            ListMultipartUploadParts("s3:ListMultipartUploadParts"),

            PutObject("s3:PutObject"),

            GetBucketLocation("s3:GetBucketLocation"),

            ListBucket("s3:ListBucket"),

            ListBucketMultipartUploads("s3:ListBucketMultipartUploads");

            private String action;

            Action(String action) {
                this.action = action;
            }
        }
    }


    static BucketPolicy getBucketPolicy(String bucketName) {
        BucketPolicy bucketPolicy = new BucketPolicy();
        List<BucketPolicy.Statement> statements = new ArrayList<>();
        BucketPolicy.Statement statement1 = new BucketPolicy.Statement();
        statement1.setResource(Arrays.asList("arn:aws:s3:::" + bucketName));
        statement1.setAction(Arrays.asList(BucketPolicy.Action.GetBucketLocation.action
                , BucketPolicy.Action.ListBucket.action,
                BucketPolicy.Action.ListBucketMultipartUploads.action));
        statements.add(statement1);

        BucketPolicy.Statement statement2 = new BucketPolicy.Statement();
        statement2.setResource(Arrays.asList("arn:aws:s3:::" + bucketName + "/*"));
        statements.add(statement2);
        bucketPolicy.setStatement(statements);
        return bucketPolicy;
    }
}



